package me.impl;

import me.Virginia;

import java.util.ArrayList;
import java.util.List;

/**
 * 维吉尼亚密码，单词提示
 * 密文：cipher
 * 明文：plain
 * 密钥：key
 *
 * @author Rainh
 * */
public class VirginiaImpl implements Virginia {

    //定义公共list为添加空格
    public static List<Integer> list = new ArrayList<Integer>();
    //实例化自己的方法
//    Virginia v = new VirginiaImpl();        //多态写法

    //返回自己
    private static VirginiaImpl instance = new VirginiaImpl();

    public static VirginiaImpl getInstance() {
        return instance;
    }



    @Override
    public int[] plainToInts(String plain) {
        String oldPlain = plain.toLowerCase();    //先变成小写
        char[] oldChars = oldPlain.toCharArray();
        for (int i = 0; i < oldChars.length; i++) {
            if(oldChars[i] ==' ')
            {//如果字符串是空格，加入到list列表里，方便等会直接插入
                list.add(i);
            }
        }
        //如果不加入这个，list会溢出
        list.add(oldChars.length);
        //替换成除去空字符的新字符串
        String newPlain = oldPlain.replace(" ","").toLowerCase();
        char[] newChars = newPlain.toCharArray();
        int[] ints = new int[newChars.length];

        //将数组串转换成数字串
        for (int i = 0; i < newChars.length; i++) {
            ints[i] = newChars[i]-97;
        }
//        for (int i = 0; i < ints.length; i++) {
//            System.out.println(ints[i]);
//        }
        return ints;
    }

    @Override
    public int[] cipherToInts(String cipher) {

        //直接调用自己的明文方法就行了
//        return v.plainToInts(cipher);
        return VirginiaImpl.getInstance().plainToInts(cipher);

    }

    @Override
    public int[] keyToInts(String key) {

        String oneKey = key.toLowerCase();    //先变成小写
        char[] oldChars = oneKey.toCharArray();
        List<Character> charList = new ArrayList<Character>();
        //由于维吉尼亚密码不能有重复的字符，所以将数组转换成list集合，方便剔除出去
        for (char oldChar : oldChars) {
            charList.add(oldChar);
        }
        //       System.out.println("剔除前的集合是"+charList);
        //先找重复的数组，然后剔除掉
        for (int i = 0; i < charList.size(); i++) {
            for (int j = i+1; j < charList.size(); j++) {

                if(charList.get(i)==charList.get(j))
                {
                    //如果有相同的，就把后面的那个相同的移除掉，一定是移除后面的，而且必须是指向它的位置，不能是它的名称
                    //charList.remove(i);   错误
                    //charList.remove(charList.get(i));   错误
                    //charList.remove(charList.get(j));   错误
                    charList.remove(j);
                    //然后再往回走一步
                    j-=1;
                }
            }
        }
//        System.out.println("剔除后的集合是"+charList);
        int[] ints = new int[charList.size()];
        //将数组串转换成数字串
        for (int i = 0; i < charList.size(); i++) {
            ints[i] = charList.get(i)-97;
        }
        return ints;

    }

    @Override
    public char[] plainToCipherByKey(int[] plains, int[] keys) {
        //创建一个与明文相同长度的密钥数组
        int[] intKeys = new int[plains.length];
        //将短的密钥数组转换成大的密钥数组，循环给
        for (int i = 0; i < plains.length; i++) {
            intKeys[i] = keys[i%keys.length];
        }
        //用于接收密文的数字数组
        int[] ints = new int[plains.length];
        //遍历接收密文
        for (int i = 0; i < plains.length; i++) {
            if(plains[i]==32)
            {//如果说，这里面是一个空格，那么不让它们相加，直接赋值给密文32
                ints[i] = 32;
                continue;
            }
            //密钥和明文相加的新的密文数字
            ints[i] = (plains[i]+intKeys[i])%26;
        }
        //创建接收的密文数组
        char[] chars = new char[ints.length];
        //将接收的密文转换成char数组
        for (int i = 0; i < ints.length; i++) {
            //还原成char数组
            chars[i] = (char)(ints[i]+97);
        }
        return chars;
    }

    @Override
    public char[] cipherToPlainByKey(int[] cipher, int[] keys) {

        //创建一个与密文相同长度的密钥数组
        int[] intKeys = new int[cipher.length];
        //将短的密钥数组转换成大的密钥数组，循环给
        for (int i = 0; i < cipher.length; i++) {
            intKeys[i] = keys[i%keys.length];
        }
        //用于接收明文的数字数组
        int[] ints = new int[cipher.length];
        //遍历接收密文
        for (int i = 0; i < cipher.length; i++) {
            if(cipher[i]==32)
            {//如果说，这里面是一个空格，那么不让它们相加，直接赋值给明文32
                ints[i] = 32;
                continue;
            }
            //密文加上26减去密钥余26就是明文的字符
//            ints[i] = (cipher[i]+intKeys[i])%26;
            ints[i] = (cipher[i]+26-intKeys[i])%26;
        }
        //创建接收的明文数组
        char[] chars = new char[ints.length];
        //将接收的密文转换成char数组
        for (int i = 0; i < ints.length; i++) {
            //还原成char数组
            chars[i] = (char)(ints[i]+97);
        }
        return chars;

    }

    @Override
    public String getResults(char[] chars) {
        //将转换成的明文或密文数组展示出来
        StringBuilder cipher = new StringBuilder();
        //定义一个计数器
        int temp = 0;
        for (int i = 0; i < chars.length; i++) {
            //这里有个大问题，如若空格很多怎么办？
            if(i+temp==list.get(temp))
            {//如果这个数字等于藏在list列表里里面的第一个空格计数，那么应向插入空格
                cipher.append(" ");
                temp++;
            }
            cipher.append(chars[i]);
        }
        //明文全部转换成密文后，list集合应当全部设置为空，为了下一次的加解密时候list仍然能够记录空格的位置
        list = new ArrayList<Integer>();
//        System.out.println("密文是"+cipher.toString());
        return cipher.toString();
    }

    @Override
    public void getCipherByPlainAndKey(String plain, String key) {

//        String cipher = getResults(v.plainToCipherByKey(v.plainToInts(plain),v.keyToInts(key)));

        String cipher = VirginiaImpl.getInstance().getResults(VirginiaImpl.getInstance().plainToCipherByKey(VirginiaImpl.getInstance().plainToInts(plain),VirginiaImpl.getInstance().keyToInts(key)));

        System.out.println("密文是"+cipher);

    }

    @Override
    public void getPlainByCipherAndKey(String cipher, String key) {

        String plains = VirginiaImpl.getInstance().getResults(VirginiaImpl.getInstance().cipherToPlainByKey(VirginiaImpl.getInstance().cipherToInts(cipher), VirginiaImpl.getInstance().keyToInts(key)));

        System.out.println("明文是"+plains);

    }

    public static void main(String[] args) {

        VirginiaImpl.getInstance().getCipherByPlainAndKey("fsd hdrgf s","hrewfgxcbfgh");
        VirginiaImpl.getInstance().getPlainByCipherAndKey("mjh dixdh t","hrewfgxcbfgh");


    }
}
